package main

import (
	"fmt"
	"strings"
)

var predictionTable = map[string]map[string]string{
	"E": {
		"num": "E -> T",
		"+":   "E -> E + T",
	},
	"T": {
		"num": "T -> num",
	},
}

type Stack []string

func (s *Stack) Push(v string) {
	*s = append(*s, v)
}

func (s *Stack) Pop() string {
	if len(*s) == 0 {
		return ""
	}
	index := len(*s) - 1
	element := (*s)[index]
	*s = (*s)[:index]
	return element
}

func (s *Stack) Top() string {
	if len(*s) == 0 {
		return ""
	}
	return (*s)[len(*s)-1]
}

func isTerminal(s string) bool {
	return s == "+" || s == "$" || (len(s) == 1 && s[0] >= '0' && s[0] <= '9')
}

func PredictiveParser(input string) bool {
	inputTokens := strings.Fields(input)
	inputTokens = append(inputTokens, "$")

	stack := Stack{"$", "E"}
	inputIndex := 0

	for len(stack) > 0 {
		top := stack.Top()
		currentToken := inputTokens[inputIndex]
		fmt.Printf("Stack: %v, Input: %s, inputIndex: %d\n", stack, currentToken, inputIndex)
		if top == currentToken {
			fmt.Println(1)
			stack.Pop()
			inputIndex++
		} else if isTerminal(top) {
			fmt.Println(2)
			return false
		} else {
			fmt.Println(3)
			production, ok := predictionTable[top][currentToken]
			fmt.Println(top, currentToken)
			if !ok {
				return false
			}
			stack.Pop()
			splitResult := strings.Split(production, "->")
			rhs := strings.Fields(splitResult[1])

			for i := len(rhs) - 1; i >= 0; i-- {
				stack.Push(rhs[i])
			}
		}
	}

	return inputIndex == len(inputTokens)
}

func main() {
	input := "2 + 3"
	if PredictiveParser(input) {
		fmt.Println("Parsing successful.")
	} else {
		fmt.Println("Parsing failed.")
	}
}
